package com.huayi.datagovernance.utils.fastjson;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.lang.Console;
import cn.hutool.core.util.RandomUtil;
import com.alibaba.fastjson.*;
import com.alibaba.fastjson.parser.Feature;
import com.alibaba.fastjson.parser.deserializer.ExtraProcessor;
import com.alibaba.fastjson.parser.deserializer.ExtraTypeProvider;
import com.alibaba.fastjson.serializer.*;
import org.junit.Assert;
import org.junit.Test;

import java.io.*;
import java.lang.reflect.Type;
import java.nio.charset.StandardCharsets;
import java.util.*;

/**
 * Fastjson 示例
 * @Author 吴大龙
 * @Date 2021/4/17 12:03
 */
public class FastJsonDemo {

    /**
     * Fastjson 支持循环引用，并且是缺省打开的。
     *
     * 当序列化后的JSON传输到浏览器或者其他语言中，这些json解析器不支持循环引用，从而导致数据丢失。
     * 你可以关闭fastjson的循环引用支持。关闭引用检测，还能够提升序列化时的性能。
     */
    @Test
    public void test1(){
        Car bc = new Car("奔驰");
        User u1 = new User("1","阿牛",bc);
        User u2 = new User("2","阿猫",bc);
        List<User> userList = ListUtil.list(true, u1, u2);
        /* JSON序列化时，同个对象会出现引用的情况，可能会导致浏览器无法解析获取 $ref 对象
         * 语法	         描述
         *{"$ref":"$"}	引用根对象
         *{"$ref":"@"}	引用自己
         *{"$ref":".."}	引用父对象
         *{"$ref":"../.."}	引用父对象的父对象
         *{"$ref":"$.members[0].reportTo"}	基于路径的引用
         * 输出结果：[{"car":{"brand":"奔驰"},"id":"1","name":"阿牛"},{"car":{"$ref":"$[0].car"},"id":"2","name":"阿猫"}]
         */
        Console.log(JSON.toJSONString(userList));
        //非全局关闭
        //输出结果：[{"car":{"brand":"奔驰"},"id":"1","name":"阿牛"},{"car":{"brand":"奔驰"},"id":"2","name":"阿猫"}]
        Console.log(JSON.toJSONString(userList, SerializerFeature.DisableCircularReferenceDetect));
        //全局关闭 循环引用检测，一方面也能提高效率
        JSON.DEFAULT_GENERATE_FEATURE |= SerializerFeature.DisableCircularReferenceDetect.getMask();
        Console.log(JSON.toJSONString(userList));
    }

    /**
     * fastjson主要的API(序列化和反序劣化)
     */
    @Test
    public void test2() throws IOException {
        //======================序列化===============================
        User user = new User("1","阿牛",new Car("法拉利"));
        //序列化 JSON.toJSONString(obj);
        //将Java对象序列化为JSON字符串，支持各种各种Java基本类型和JavaBean
        Console.log(JSON.toJSONString(user));
        // 将Java对象序列化为JSON字符串，返回JSON字符串的utf-8 bytes
        System.out.println(JSON.toJSONBytes(user));
        // 将Java对象序列化为JSON字符串，写入到Writer中
        BufferedWriter bw = new BufferedWriter(new FileWriter("C:/Users/AORUS/Desktop/测试图片/writeJSONString.txt"));
        JSON.writeJSONString(bw, user, SerializerFeature.DisableCircularReferenceDetect);
        // 将Java对象序列化为JSON字符串，按UTF-8编码写入到OutputStream中
        BufferedOutputStream bo = new BufferedOutputStream(new FileOutputStream("C:/Users/AORUS/Desktop/测试图片/writeJSONString.txt",true));
        final String  LINE_SEPARATOR = System.getProperty("line.separator");//获取当前系统换行符
        bo.write(LINE_SEPARATOR.getBytes());//换行
        JSON.writeJSONString(bo, StandardCharsets.UTF_8, "将Java对象序列化为JSON字符串，按UTF-8编码写入到OutputStream中");
        bo.close();//关闭后输出内容


        //======================反序列化===============================
        //反序列化 JSON.parseObject(obj)
        //将JSON字符串反序列为JSONObject
        String userJson = "{\"id\":\"1\",\"name\":\"阿波\",\"car\":{\"brand\":\"宝骏\"}}";
        JSONObject user2 = JSON.parseObject(userJson);
        Console.log(user2);
        // 将utf-8的字节数组反序列化为JavaBean
        User user1 = JSON.parseObject(userJson.getBytes(), User.class);
        Console.log(user1);


        //反序列化，指定java类型 JSON.parseObject(obj)
        //将JSON字符串反序列化为JavaBean
        String user2Json = "{\"id\":\"5\",\"name\":\"阿s\",\"car\":{\"brand\":\"大牛\"}}";
        User user3 = JSON.parseObject(user2Json, User.class, Feature.AllowUnQuotedFieldNames);
        Console.log(user3);

        //泛型反序列化 指定类型 JSON.parseObject("...", new TypeReference<List<User>>() {}
        //将JSON字符串反序列化为泛型类型的JavaBean
        String userListJson = "[{\"id\": \"3\",\"name\": \"阿土\",\"car\":{\"brand\": \"哈佛H6\"}},{\"id\": \"4\",\"name\": \"阿龙\",\"car\":{\"brand\": \"特斯拉\"}}]";
        Type type = new TypeReference<List<User>>() {}.getType();
        // List<User> userList = JSON.parseObject(userListJson, new TypeReference<List<User>>() {});
        List<User> userList = JSON.parseObject(userListJson, type);
        Console.log(userList);

    }

    /**
     * fastjson 处理日期
     *
     * 反序列化能够自动识别如下日期格式：
     * ISO-8601日期格式
     * yyyy-MM-dd
     * yyyy-MM-dd HH:mm:ss
     * yyyy-MM-dd HH:mm:ss.SSS
     * 毫秒数字
     * 毫秒数字字符串
     * .NET JSON日期格式
     * new Date(198293238)
     */
    @Test
    public void test3(){
        DateTime now = DateTime.now();
        //日期 转 指定格式的字符串
        String dateFormat = JSON.toJSONStringWithDateFormat(now, "yyyy-MM-dd HH:mm:ss.SSS");
        Console.log(dateFormat);//"2021-04-17 18:48:16.695"

        //使用ISO-8601日期格式
        String dateFormat1 = JSON.toJSONString(now, SerializerFeature.UseISO8601DateFormat);
        Console.log(dateFormat1);//"2021-04-17T18:48:16.695+08:00"

        //全局修改日期格式
        JSON.DEFFAULT_DATE_FORMAT = "yyyy-MM-dd";
        String dateFormat2 = JSON.toJSONString(now, SerializerFeature.WriteDateUseDateFormat);
        Console.log(dateFormat2);

        /*9. 如何定制序列化？
           你可以使用SimplePrePropertyFilter过滤字段，
           详细看这里：https://github.com/alibaba/fastjson/wiki/%E4%BD%BF%E7%94%A8SimplePropertyPreFilter%E8%BF%87%E6%BB%A4%E5%B1%9E%E6%80%A7
           关于定制序列化，详细的介绍看这里：https://www.w3cschool.cn/fastjson/fastjson-serializefilter.html
        */
    }

    /**
     * JSONField 介绍
     * 注意：1、若属性是私有的，必须有set*方法。否则无法反序列化。
     */
    @Test
    public void test4(){
        // 注解 @JSONField
       /* public @interface JSONField {
            // 配置序列化和反序列化的顺序，1.1.42版本之后才支持
            int ordinal() default 0;
            // 指定字段的名称
            String name() default "";
            // 指定字段的格式，对日期格式有用
            String format() default "";
            // 是否序列化
            boolean serialize() default true;
            // 是否反序列化
            boolean deserialize() default true;
        }*/

        // JSONField配置方式
        // FieldInfo可以配置在getter/setter方法或者字段上。例如：
        // 2.1 配置在getter/setter上
        /*public class A {
            private int id;

            @JSONField(name="ID")
            public int getId() {return id;}
            @JSONField(name="ID")
            public void setId(int value) {this.id = id;}
        }*/

        // 2.2 配置在field上
       /* public class A {
            @JSONField(name="ID")
            private int id;

            public int getId() {return id;}
            public void setId(int value) {this.id = id;}
        }*/

        // 3. 使用format配置日期格式化
       /* public class A {
            // 配置date序列化和反序列使用yyyyMMdd日期格式
            @JSONField(format="yyyyMMdd")
            public Date date;
        }*/

        // 4. 使用serialize/deserialize指定字段不序列化
        /*public class A {
            @JSONField(serialize=false)
            public Date date;
        }

        public class A {
            @JSONField(deserialize=false)
            public Date date;
        }*/

        /* 5. 使用ordinal指定字段的顺序
        缺省fastjson序列化一个java bean，是根据fieldName的字母序进行序列化的，
        你可以通过ordinal指定字段的顺序。这个特性需要1.1.42以上版本。*/
       /* public static class VO {
            @JSONField(ordinal = 3)
            private int f0;

            @JSONField(ordinal = 2)
            private int f1;

            @JSONField(ordinal = 1)
            private int f2;
        }*/

        /*6. 使用serializeUsing制定属性的序列化类
        在fastjson 1.2.16版本之后，JSONField支持新的定制化配置serializeUsing，
        可以单独对某一个类的某个属性定制序列化，比如：*/
        /*public static class Model {
            @JSONField(serializeUsing = ModelValueSerializer.class)
            public int value;
        }
        public static class ModelValueSerializer implements ObjectSerializer {
            @Override
            public void write(JSONSerializer serializer, Object object, Object fieldName, Type fieldType,
                              int features) throws IOException {
                Integer value = (Integer) object;
                String text = value + "元";
                serializer.write(text);
            }
        }*/
        // 测试代码
        /*Model model = new Model();
        model.value = 100;
        String json = JSON.toJSONString(model);
        Assert.assertEquals("{\"value\":\"100元\"}", json);*/

        /*7、JSONField alternateNames
        在fastjson在1.2.21版本中提供了一个借鉴自gson的特性，支持反序列化时使用多个不同的字段名称，
        使用的方式是配置JSONField的alternateNames。  */
        // Demo 示例
        /*public static class Model {
            public int id;

            @JSONField(alternateNames = {"user", "person"})
            public String name;
        }

        String jsonVal0 = "{\"id\":5001,\"name\":\"Jobs\"}";
        String jsonVal1 = "{\"id\":5382,\"user\":\"Mary\"}";
        String jsonVal2 = "{\"id\":2341,\"person\":\"Bob\"}";

        Model obj0 = JSON.parseObject(jsonVal0, Model.class);
        assertEquals(5001, obj0.id);
        assertEquals("Jobs", obj0.name);

        Model obj1 = JSON.parseObject(jsonVal1, Model.class);
        assertEquals(5382, obj1.id);
        assertEquals("Mary", obj1.name);

        Model obj2 = JSON.parseObject(jsonVal2, Model.class);
        assertEquals(2341, obj2.id);
        assertEquals("Bob", obj2.name);*/

        /*8、JSONField jsonDirect
        在fastjson-1.2.12版本中，JSONField支持一个新的配置项jsonDirect，它的用途是：
        当你有一个字段是字符串类型，里面是json格式数据，你希望直接输入，而不是经过转义之后再输出。*/
        // Model
        /*public static class Model {
            public int id;
            @JSONField(jsonDirect=true)
            public String value;
        }*/
        // 使用
       /* model.id = 1001;
        model.value = "{}";
        String json = JSON.toJSONString(model);
        Assert.assertEquals("{\"id\":1001,\"value\":{}}", json);*/
    }

    /**
     * JSONPath介绍
     * fastjson 1.2.0之后的版本支持JSONPath。这是一个很强大的功能，
     * 可以在java框架中当作对象查询语言（OQL）来使用。
     * 建议缓存JSONPath对象，这样能够提高求值的性能。
     * 使用参考：https://www.w3cschool.cn/fastjson/fastjson-jsonpath.html
     */
    @Test
    public void test5(){
        //  求值，静态方法
        // Object eval(Object rootObject, String path);

        // 计算Size，Map非空元素个数，对象非空元素个数，Collection的Size，数组的长度。其他无法求值返回-1
        // static int size(Object rootObject, String path);

        // 是否包含，path中是否存在对象
        // static boolean contains(Object rootObject, String path)

        // 是否包含，path中是否存在指定值，如果是集合或者数组，在集合中查找value是否存在
        // boolean containsValue(Object rootObject, String path, Object value)

        // 修改制定路径的值，如果修改成功，返回true，否则返回false
        // static boolean set(Object rootObject, String path, Object value)

        // 在数组或者集合中添加元素
        // static boolean array_add(Object rootObject, String path, Object... values)

        // API 示例
        // 5.1 例1
        class Entity {
            private Integer id;
            private String name;
            private Object value;

            public Entity() {}
            public Entity(Integer id, Object value) { this.id = id; this.value = value; }
            public Entity(Integer id, String name) { this.id = id; this.name = name; }
            public Entity(String name) { this.name = name; }

            public Integer getId() { return id; }
            public Object getValue() { return value; }
            public String getName() { return name; }

            public void setId(Integer id) { this.id = id; }
            public void setName(String name) { this.name = name; }
            public void setValue(Object value) { this.value = value; }
        }

        Entity entity = new Entity(123, new Object());
        Assert.assertSame(entity.getValue(), JSONPath.eval(entity, "$.value"));
        Assert.assertTrue(JSONPath.contains(entity, "$.value"));
        Assert.assertTrue(JSONPath.containsValue(entity, "$.id", 123));
        Assert.assertTrue(JSONPath.containsValue(entity, "$.value", entity.getValue()));
        Assert.assertEquals(2, JSONPath.size(entity, "$"));
        Assert.assertEquals(0, JSONPath.size(new Object[0], "$"));

        //5.2 例2
        //读取集合多个元素的某个属性
        List<Entity> entities = new ArrayList<Entity>();
        entities.add(new Entity("wenshao"));
        entities.add(new Entity("ljw2083"));

        List<String> names = (List<String>)JSONPath.eval(entities, "$.name"); // 返回enties的所有名称
        Assert.assertSame(entities.get(0).getName(), names.get(0));
        Assert.assertSame(entities.get(1).getName(), names.get(1));
        // Console.log(names);

        // 5.3 例3
        // 返回集合中多个元素
        List<Entity> entities1 = new ArrayList<Entity>();
        entities1.add(new Entity("wenshao"));
        entities1.add(new Entity("ljw2083"));
        entities1.add(new Entity("Yako"));

        List<Entity> result1 = (List<Entity>)JSONPath.eval(entities1, "[1,2]"); // 返回下标为1和2的元素
        Assert.assertEquals(2, result1.size());
        Assert.assertSame(entities1.get(1), result1.get(0));
        Assert.assertSame(entities1.get(2), result1.get(1));

        // 5.4 例4
        // 按范围返回集合的子集
        List<Entity> entities2 = new ArrayList<Entity>();
        entities2.add(new Entity("wenshao"));
        entities2.add(new Entity("ljw2083"));
        entities2.add(new Entity("Yako"));

        List<Entity> result2 = (List<Entity>)JSONPath.eval(entities2, "[0:2]"); // 返回下标从0到2的元素
        Assert.assertEquals(3, result2.size());
        Assert.assertSame(entities2.get(0), result2.get(0));
        Assert.assertSame(entities2.get(1), result2.get(1));
        Assert.assertSame(entities2.get(2), result2.get(2));

        // 5.5 例5
        // 通过条件过滤，返回集合的子集
        List<Entity> entities3 = new ArrayList<Entity>();
        entities3.add(new Entity(1001, "ljw2083"));
        entities3.add(new Entity(1002, "wenshao"));
        entities3.add(new Entity(1003, "yakolee"));
        entities3.add(new Entity(1004, null));

        List<Object> result3 = (List<Object>) JSONPath.eval(entities3, "[id in (1001)]");
        Assert.assertEquals(1, result3.size());
        Assert.assertSame(entities3.get(0), result3.get(0));

        // 5.6 例6
        // 根据属性值过滤条件判断是否返回对象，修改对象，数组属性添加元素
        Entity entity4 = new Entity(1001, "哇哦");
        Assert.assertSame(entity4 , JSONPath.eval(entity4, "[id = 1001]"));
        Assert.assertNull(JSONPath.eval(entity4, "[id = 1002]"));

        JSONPath.set(entity4, "id", 123456); //将id字段修改为123456
        Assert.assertEquals(123456, entity4.getId().intValue());

        JSONPath.set(entity4, "value", "普拉斯"); //将value字段赋值为长度为0的数组
        JSONPath.arrayAdd(entity4, "value", 1, 2, 3); //将value字段的数组添加元素1,2,3 没效果
        System.out.println(entity4);
    }

    /**
     * Fastjson API Stream
     * 当需要处理超大JSON文本时，需要Stream API，在fastjson-1.1.32版本中开始提供Stream API。
     */
    @Test
    public void test6() throws IOException {
        Console.log("===============序列化=================");
        /*超大JSON数组序列化 写入文件
        如果你的JSON格式是一个巨大的JSON数组，有很多元素，则先调用startArray，然后挨个写入对象，然后调用endArray。*/
        JSONWriter writer = new JSONWriter(new FileWriter("C:/Users/AORUS/Desktop/测试图片/WriteBigJson"));
        writer.startArray();
        for (int i = 0; i < 10; ++i) {
            String str = RandomUtil.randomString(5); //随机生成5位的字符串（数字和字母） c4vkb
            Console.log(str);
            writer.writeKey(str);
        }
        writer.endArray();
        writer.close();

        /*超大JSON对象序列化
        如果你的JSON格式是一个巨大的JSONObject，有很多Key/Value对，则先调用startObject，然后挨个写入Key和Value，然后调用endObject。*/
        JSONWriter writer2 = new JSONWriter(new FileWriter("C:/Users/AORUS/Desktop/测试图片/WriteBigJsonObj"));
        String baseString = "吴大龙周润发牛的滑冯提莫野小马兔子牙陈言妍像少农隔壁灬老王じ☆ve萌爱灬牛奶煮萝莉爱ˇ扑啦猫~wёл兔兔ㄣ╭曾εゎ";
        writer2.startObject();
        for (int i = 0; i < 10; ++i) {
            Map<String, Object> map = BeanUtil.beanToMap(new User(String.valueOf(i+1), RandomUtil.randomString(baseString,3),null));
            Set<Map.Entry<String, Object>> entries = map.entrySet();
            Console.log(entries);
            entries.forEach(e->{
                writer2.writeKey(e.getKey());
                writer2.writeValue(e.getValue());
            });
        }
        writer2.endObject();
        writer2.close();

        Console.log("===============反序列化=================");
        // 超大JSON数组反序列化
        JSONReader reader1 = new JSONReader(new FileReader("C:/Users/AORUS/Desktop/测试图片/WriteBigJson"));
        List<String> list1 = new ArrayList<>();
        reader1.startArray();
        while(reader1.hasNext()) {
            list1.add(reader1.readString());

        }
        reader1.endArray();
        reader1.close();
        Console.log(list1);

        // 超大JSON对象反序列化
        JSONReader reader2 = new JSONReader(new FileReader("C:/Users/AORUS/Desktop/测试图片/WriteBigJsonObj"));
        List<User> list2 = new ArrayList<>();
        reader2.startObject();
        while(reader2.hasNext()) {
            HashMap<String, Object> map = new HashMap<>();
            String key = reader2.readString();
            // Console.log(key);
            Object value = reader2.readObject();
            // Console.log(value);
            map.put(key, value);
            list2.add(BeanUtil.toBean(map, User.class));
        }
        reader2.endObject();
        reader2.close();
        Console.log(list2);
    }

    /**
     * Fastjson API ParseProcess简介
     * ParseProcess是编程扩展定制反序列化的接口。fastjson支持如下ParseProcess：
     * ExtraProcessor 用于处理多余的字段
     * ExtraTypeProvider 用于处理字段时提供类型信息
     */
    @Test
    public void test7(){
        // 使用ExtraProcessor
        // Vo必须为public修饰的类，否则 object 会为 null
        ExtraProcessor processor1 = new ExtraProcessor() {
            public void processExtra(Object object, String key, Object value) {
                //读取的是Vo里不存在的字段，所以 key 为 name
                VO vo = (VO) object;
                vo.getAttributes().put(key, value); //把 name 放到 map中
            }
        };

        VO vo = JSON.parseObject("{\"id\":123,\"name\":\"abc\"}", VO.class, processor1);
        Assert.assertEquals(123, vo.getId());
        Assert.assertEquals("abc", vo.getAttributes().get("name"));

        // 使用ExtraTypeProvider 为多余的字段提供类型
        class MyExtraProcessor implements ExtraProcessor, ExtraTypeProvider {
            public void processExtra(Object object, String key, Object value) {//后执行
                VO vo = (VO) object;
                vo.getAttributes().put(key, value);
            }

            public Type getExtraType(Object object, String key) {//先执行
                if ("value".equals(key)) {
                    return int.class;
                }
                return null;
            }
        };
        ExtraProcessor processor = new MyExtraProcessor();

        VO vo2 = JSON.parseObject("{\"id\":123,\"value\":\"123456\"}", VO.class, processor);
        Assert.assertEquals(123, vo2.getId());
        Assert.assertEquals(123456, vo2.getAttributes().get("value")); // value本应该是字符串类型的，通过getExtraType的处理变成Integer类型了。
    }

    /**
     * Fastjson API SerializeFilter简介
     * SerializeFilter是通过编程扩展的方式定制序列化。fastjson支持6种SerializeFilter，用于不同场景的定制序列化。
     * PropertyPreFilter 根据PropertyName判断是否序列化
     * PropertyFilter 根据PropertyName和PropertyValue来判断是否序列化
     * NameFilter 修改Key，如果需要修改Key,process返回值则可
     * ValueFilter 修改Value
     * BeforeFilter 序列化时在最前添加内容
     * AfterFilter 序列化时在最后添加内容
     */
    @Test
    public void test8(){

        // 1. PropertyFilter 根据PropertyName和PropertyValue来判断是否序列化
        //可以通过扩展实现根据object或者属性名称或者属性值进行判断是否需要序列化。例如：
        PropertyFilter filter = new PropertyFilter() {
            @Override
            public boolean apply(Object source, String name, Object value) {
                // 只序列化 id字段 并且id值大于等于100
                if ("id".equals(name)){
                    int id = ((Integer) value).intValue(); //value为字段值
                    return id >= 100;
                }
                return false;//不序列化
            }
        };
        VO vo1 = new VO();
        vo1.setId(100);
        vo1.getAttributes().put("name","鱼蛋头");
        VO vo2 = new VO();
        vo2.setId(11);
        vo2.getAttributes().put("name","鲨鱼丫头");
        List<VO> vos = ListUtil.list(false, vo1, vo2);
        System.out.println(JSON.toJSONString(vos, filter)); // 序列化的时候传入filter

        // 2. PropertyPreFilter 根据PropertyName判断是否序列化
        // 和PropertyFilter不同只根据object和name进行判断，在调用getter之前，这样避免了getter调用可能存在的异常
        PropertyPreFilter preFilter = new PropertyPreFilter() {
            @Override
            public boolean apply(JSONSerializer serializer, Object value, String name) {
                //只序列化 id属性
                if ("id".equals(name)){
                    Console.log(value);//value为vo对象
                    return true;
                }
                return false;
            }
        };
        System.out.println(JSON.toJSONString(vos, preFilter));

        // 3. NameFilter 序列化时修改Key
        // 如果需要修改Key,process返回值则可
        NameFilter nameFilter = new NameFilter() {
            @Override
            public String process(Object source, String name, Object value) {
                // 修改id的字段名 id后面拼接个 $ 符号
                if ("id".equals(name)) {
                    return name + "$";
                }
                return name;
            }
        };
        System.out.println(JSON.toJSONString(vos, nameFilter));
        // fastjson内置一个PascalNameFilter，用于输出将首字符大写的Pascal风格。 例如：
        System.out.println(JSON.toJSONString(vos, new PascalNameFilter()));

        // 4. ValueFilter 序列化是修改Value
        ValueFilter valueFilter = new ValueFilter() {
            @Override
            public Object process(Object object, String name, Object value) {
                // 修改id的值 后面拼接个 # 符号
                if ("id".equals(name)) {
                    int id = ((Integer) value).intValue();
                    return id + "$";
                }
                return value;
            }
        };
        System.out.println(JSON.toJSONString(vos, valueFilter));

        // 5. BeforeFilter 序列化时在最前添加内容
        // 在序列化对象的所有属性之前执行某些操作,例如调用 writeKeyValue 添加内容
        BeforeFilter beforeFilter = new BeforeFilter() {
            //会修改原始对象的属性
            // name 值 后面拼接 "%%"
            @Override
            public void writeBefore(Object object) {
                VO vo = (VO) object;
                vo.getAttributes().put("name",vo.getAttributes().get("name")+"%%");
            }
        };
        System.out.println(JSON.toJSONString(vos, beforeFilter));
        System.out.println(vos);

        // 6. AfterFilter 序列化时在最后添加内容
        // 在序列化对象的所有属性之后执行某些操作,例如调用 writeKeyValue 添加内容
        AfterFilter afterFilter = new AfterFilter() {
            //会修改原始对象的属性
            @Override
            public void writeAfter(Object object) {
                VO vo = (VO) object;
                vo.setId(999);
                vo.getAttributes().put("name",vo.getAttributes().get("name")+"&&");
                // Console.log(vo);
            }
        };
        JSON.toJSONString(vos, afterFilter);
        System.out.println(vos);


    }


}
